package com.infra.micro.oss.domain.service.impl;

import com.infra.common.enums.ChecksumEnum;
import com.infra.common.enums.MimeTypeEnum;
import com.infra.common.resp.Response;
import com.infra.common.util.ChecksumUtils;
import com.infra.micro.oss.domain.db.entity.FileInfoPO;
import com.infra.micro.oss.domain.model.dto.ThumbnailDTO;
import com.infra.micro.oss.domain.service.UploadService;
import com.infra.micro.oss.model.vo.BizFileVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;

@Service
@Transactional
public class UploadServiceImpl extends BaseFileService implements UploadService {
    private static final List<String> IMAGE_MIME_TYPE_LIST = Arrays.asList(MimeTypeEnum.IMAGE_BMP.getMessage(),
            MimeTypeEnum.IMAGE_JPEG.getMessage(),
            MimeTypeEnum.IMAGE_JPEG.getMessage(),
            MimeTypeEnum.IMAGE_PNG.getMessage());

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Response<List<BizFileVO>> upload(HttpServletRequest request) throws IOException {
        final String userId = request.getParameter("userId");
        final String appId = request.getParameter("appId");
        final String thumbnail = request.getParameter("thumbnail");

        List<BizFileVO> bizFileVOList = upload2Oss(((StandardMultipartHttpServletRequest) request), thumbnail);

        if (CollectionUtils.isEmpty(bizFileVOList)) {
            return Response.error("上传失败，未检测到文件");
        }

        // 设置用户ID
        bizFileVOList.forEach(item -> {
            item.setUserId(userId);
            item.setAppId(appId);
        });

        // 批量落地业务文件信息
        int ret = bizInfoRepository.batchInsert(bizFileVOList);
        return Response.success(bizFileVOList, "成功上传" + ret + "个文件");
    }

    /**
     * 文件上传
     *
     * @param request
     * @return
     */
    public List<BizFileVO> upload2Oss(MultipartHttpServletRequest request, String thumbnail) throws IOException {
        Iterator<String> fileNames = request.getFileNames();

        List<BizFileVO> files = new ArrayList<>();
        while (fileNames.hasNext()) {
            List<MultipartFile> multipartFileList = request.getFiles(fileNames.next());
            for (MultipartFile mpf : multipartFileList) {
                final String fileName = mpf.getOriginalFilename();
                LOGGER.info(mpf.getOriginalFilename() + " uploaded! file size: " + files.size());

                //计算文件SHA/md5值
                String sha;
                String md5;
                try {
                    sha = ChecksumUtils.getValue(mpf.getBytes(), ChecksumEnum.SHA1);
                    md5 = ChecksumUtils.getValue(mpf.getBytes(), ChecksumEnum.MD5);
                } catch (Exception ex) {
                    LOGGER.error("获取文件SHA1,MD5异常", ex);
                    continue;
                }

                //查询SHA值是否存在
                FileInfoPO fileInfoPO = fileInfoRepository.queryBySHA(sha);
                if (fileInfoPO != null) {
                    files.add(buildBizFileVO(fileInfoPO, fileName));
                    // 生成缩略图场景
                    if (StringUtils.isNotBlank(thumbnail) && IMAGE_MIME_TYPE_LIST.contains(fileInfoPO.getMimeType().toLowerCase(Locale.ROOT))) {
                        uploadThumbnail2Oss(fileInfoPO.getFileId(), split(thumbnail, fileInfoPO.getThumbnail(), ","), mpf);
                        fileInfoPO.setThumbnail(String.join(",", merge(split(thumbnail, ","), split(fileInfoPO.getThumbnail(), ","))));
                        fileInfoRepository.update(fileInfoPO);
                    }
                    continue;
                }

                //构建文件信息入库
                fileInfoPO = buildFileInfoPO(mpf, sha, md5);
                int ret = fileInfoRepository.insert(fileInfoPO);
                if (ret > 0) {
                    // 移除
                    ossClient.removeObject(fileInfoPO.getFileId().toString());
                    // 上传
                    ossClient.putObject(fileInfoPO.getFileId().toString(), mpf.getInputStream());
                    // 生成缩略图场景
                    if (StringUtils.isNotBlank(thumbnail) && IMAGE_MIME_TYPE_LIST.contains(fileInfoPO.getMimeType().toLowerCase(Locale.ROOT))) {
                        fileInfoPO.setThumbnail(String.join(",", uploadThumbnail2Oss(fileInfoPO.getFileId(), split(thumbnail, ","), mpf)));
                        fileInfoRepository.update(fileInfoPO);
                    }

                    files.add(buildBizFileVO(fileInfoPO, fileName));
                }
            }
        }
        return files;
    }

    public List<String> uploadThumbnail2Oss(Long fileId, List<String> thumbnails, final MultipartFile multipartFile) {
        List<ThumbnailDTO> thumbnailList = getThumbnailList(thumbnails);
        List<String> result = new ArrayList<>(thumbnailList.size());
        for (ThumbnailDTO item : thumbnailList) {
            try {
                final String thumbnailSize = String.format("%d*%d", item.getWidth(), item.getHeight());
                final String thumbnailKey = String.format(THUMBNAIL_FORMAT_KEY, fileId.toString(), thumbnailSize);
                // 移除
                ossClient.removeObject(thumbnailKey);
                // 上传
                ossClient.putObject(thumbnailKey, thumbnail(multipartFile, item.getWidth(), item.getHeight()));
                result.add(thumbnailSize);
            } catch (IOException e) {
                LOGGER.error("生成缩略图上传到OSS时出现异常", e);
            }
        }

        return result;
    }
}
